/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package pr2.cruce;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import pr2.cromosoma.CromosomaPVC;

/**
 *
 * @author Gonzalo Ortiz Jaureguizar (gortiz at software.imdea.org)
 */
public class OXPosicionesPrioritarias extends EstrategiaCruce<CromosomaPVC>{

    private final ArrayList<Integer> posiciones;
    private final HashSet<Integer> seleccionados;

    public OXPosicionesPrioritarias(int size) {
        super(size);
        posiciones = new ArrayList<Integer>(size);
        for(int i = 0; i < size; i++) {
            posiciones.add(i);
        }
        seleccionados = new HashSet<Integer>(size);
    }

    private void elegir() {
        Collections.shuffle(posiciones);
        int maxSeleccionados = (int) (Math.random() * posiciones.size());
        
        seleccionados.clear();
        for(int i = 0; i < maxSeleccionados; i++) {
            seleccionados.add(posiciones.get(i));
        }
    }

    private boolean isSeleccionado(Integer posicion) {
        return seleccionados.contains(posicion);
    }

    private void intercambiar(List<Integer> padre1, List<Integer> padre2, List<Integer> h1, List<Integer> h2) {
        
        for(Integer i : seleccionados) {
            h1.set(i, padre2.get(i));
            h2.set(i, padre1.get(i));
        }
    }

    @Override
    protected void cruzar(CromosomaPVC padre1, CromosomaPVC padre2, CromosomaPVC hijo1, CromosomaPVC hijo2) {
        elegir();

        if(seleccionados.size() == posiciones.size() || seleccionados.isEmpty()) { //todos quedarian igual
            hijo1.copia(padre1);
            hijo2.copia(padre2);
            return ;
        }

        List<Integer> pg1 = padre1.getGenes();
        List<Integer> pg2 = padre2.getGenes();
        List<Integer> hg1 = hijo1.getGenes();
        List<Integer> hg2 = hijo2.getGenes();

        intercambiar(pg1, pg2, hg1, hg2);

        copiarNoSeleccionados(pg1, pg2, hg1);
        copiarNoSeleccionados(pg2, pg1, hg2);
    }

    private void copiarNoSeleccionados(List<Integer> padreActual, List<Integer> otroPadre, List<Integer> hijoActual) {
        final int size = padreActual.size();

        int indexPadre = 0;
        int indexHijo = 0;
        while(indexHijo < size) {
            if(isSeleccionado(indexHijo)) { //la posicion ya tiene valor
                indexHijo++;
                continue;
            }
            /*
             * Al llegar a aqui:
             *      + indexHijo es una posicion "sucia" (necesita valor)
             *      + indexPadre puede apuntar a un valor de la subcadena intercambiada
             */
            if(!isEnSubcadena(padreActual, otroPadre, indexPadre)) { //copiamos tal cual
                hijoActual.set(indexHijo, padreActual.get(indexPadre));
                //la siguiente vez escribiremos la posicion del hijo siguiente
                indexHijo++; //al llegar al final, desborda y el while para
            }
            else { //si esta, buscamos en la posicion siguiente

            }
            indexPadre++; //pasamos a la siguiente posicion
        }
    }
    
    private boolean isEnSubcadena(List<Integer> padreActual, List<Integer> otroPadre, int indexEnActual) {
        Integer valor = padreActual.get(indexEnActual);
        for(Integer i : seleccionados) {
            if(otroPadre.get(i) == valor) {
                return true;
            }
        }
        return false;
    }
}
